home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 May: Tool Chest / Developer CD Series May 1996 (Tool Chest) (Apple Computer) (1996).iso / Sample Code / Snippets / QuickDraw / Imageer 1.0.0d3 / source / fileIO.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-02-16  |  43.4 KB  |  1,484 lines  |  [TEXT/MPS ]

  1. /****************************************************/
  2. /*                                                    */
  3. /*    File:        fileIO.c                            */
  4. /*                                                    */
  5. /*    Program:    Imageer                                */
  6. /*                                                    */
  7. /*    By:            Jason Hodges-Harris                    */
  8. /*                                                    */
  9. /*    Created:    26/10/95  00:00:00 AM                */
  10. /*                                                    */
  11. /*    Version:    1.0.0d3                                */
  12. /*                                                    */
  13. /*    Copyright:    © 1995-96 Apple Computer, Inc.,        */ 
  14. /*                    all rights reserved.            */        
  15. /*                                                    */
  16. /****************************************************/
  17.  
  18.  
  19. /**** Macintosh Toolbox Headers *****/
  20.  
  21. #ifndef __COMPONENTS__
  22. #include <Components.h>
  23. #endif
  24.  
  25. #ifndef __CONTROLS__
  26. #include <Controls.h>
  27. #endif
  28.  
  29. #ifndef __CURSORCTL__
  30. #include <CursorCtl.h>
  31. #endif
  32.  
  33. #ifndef __DIALOGS__
  34. #include <Dialogs.h>
  35. #endif
  36.  
  37. #ifndef __FILES__
  38. #include <Files.h>
  39. #endif
  40.  
  41. #ifndef __GXGRAPHICS__
  42. #include <GXGraphics.h>
  43. #endif
  44.  
  45. #ifndef __GXMATH__
  46. #include <GXMath.h>
  47. #endif
  48.  
  49. #ifndef __IMAGECOMPRESSION__
  50. #include <ImageCompression.h>
  51. #endif
  52.  
  53. #ifndef __MEMORY__
  54. #include <Memory.h>
  55. #endif
  56.  
  57. #ifndef __PICTUTILS__
  58. #include <PictUtils.h>
  59. #endif
  60.  
  61. #ifndef __QUICKTIMECOMPONENTS__
  62. #include <QuickTimeComponents.h>
  63. #endif
  64.  
  65. #ifndef __STANDARDFILE__
  66. #include <StandardFile.h>
  67. #endif
  68.  
  69. #ifndef __STRING__
  70. #include <string.h>
  71. #endif
  72.  
  73. #ifndef __STRINGS__
  74. #include <Strings.h>
  75. #endif
  76.  
  77. #ifndef __TOOLUTILS__
  78. #include <ToolUtils.h>
  79. #endif
  80.  
  81. #ifndef __TYPES__
  82. #include <Types.h>
  83. #endif
  84.  
  85.  
  86. /****   Application headers and prototypes   ****/
  87.  
  88.  
  89. #ifndef __IMAGEERAPPHEADER__
  90. #include "Imageer.app.h"
  91. #endif
  92.  
  93. #ifndef __IMAGEERPROTOSHEADER__
  94. #include "Imageer.protos.h"
  95. #endif
  96.  
  97.  
  98. /****    Global variables    ****/
  99.  
  100. extern OSType     gLoadFileType;
  101. static OSType    gSaveFileType;
  102.  
  103.  
  104. /****    Default RGB Colors    ****/
  105.  
  106. static const RGBColor     kRGBBlack = {0x0000, 0x0000, 0x0000};
  107. static const RGBColor    kRGBWhite = {0xFFFF, 0xFFFF, 0xFFFF};
  108.  
  109.  
  110. /****    Load supported image file type    ****/
  111.  
  112. // Main function which is called when 'Open' is selected in the file menu.
  113. // Displays the custom get file dialog, which supports a pop up menu
  114. // to filter out unwanted/unwanted file types. Creates and initialises the
  115. // image window document structure dependent of the file type loaded.
  116.  
  117. #pragma segment fileSys
  118. OSErr    LoadSupportedImage(void)
  119. {
  120.     ImageDocHndl        theDocHndl = nil;
  121.     PicHandle            thePictHndl = nil;
  122.     DlgHookYDUPP        theDialogHookUPP;
  123.     FileFilterYDUPP        theDialogFileFilterUPP;
  124.     PictInfo            thePictInfo;
  125.     StandardFileReply    theSFReply;
  126.     TiffInfo            theTiffStruct;
  127.     SFTypeList            fileTypes;
  128.     Point                dlogPosition = {-1,-1};
  129.     OSErr                error = noErr;
  130.     
  131.     // Create Universal Proc Ptrs for custom Dialog functions
  132.     theDialogHookUPP = NewDlgHookYDProc(CustomGetFileHook);
  133.     theDialogFileFilterUPP = NewFileFilterYDProc(CustomFileDlogFilter);
  134.     CustomGetFile (theDialogFileFilterUPP,-1,
  135.                    fileTypes,&theSFReply,rCustomOpenDialog,
  136.                    dlogPosition,theDialogHookUPP,nil,nil,nil,nil);
  137.     DisposeRoutineDescriptor((UniversalProcPtr)theDialogHookUPP);
  138.     DisposeRoutineDescriptor((UniversalProcPtr)theDialogFileFilterUPP);
  139.     if (theSFReply.sfGood == true)
  140.     {
  141.         theDocHndl = (ImageDocHndl)NewHandle(sizeof(ImageDoc));    // create new image document
  142.         if (!theDocHndl)
  143.         {
  144.             DisplayAlert (rGenWarning,rErrMessages,iFailAllocMem);
  145.             return kFailAllocDocHndl;
  146.         }
  147.         if (theSFReply.sfType == 'qdgx')
  148.             (**theDocHndl).isUsingQDGX = true;
  149.         else
  150.             (**theDocHndl).isUsingQDGX = false;            
  151.         (**theDocHndl).theImageFileReply = theSFReply;    // copy SFReply to window Doc structure
  152.         switch (theSFReply.sfType)
  153.         {
  154.             case ('TIFF'):                                // TIFF file type
  155.                 // Set up document structure to defaults for image type
  156.                 (**theDocHndl).theFileType = TiffType;
  157.                 (**theDocHndl).theImageChanged = false;
  158.                 (**theDocHndl).theColorsPalette = nil;
  159.                 (**theDocHndl).theImageWorld = nil;
  160.                 (**theDocHndl).theVScrollBar = nil;
  161.                 (**theDocHndl).theHScrollBar = nil;
  162.                 (**theDocHndl).theUndoState = kCannotUndo;
  163.                 (**theDocHndl).hasUndoTemp = false;
  164.                 (**theDocHndl).hasRedoTemp = false;
  165.                 theTiffStruct.tiffCTabHndl = nil;        // set to nil as Color table not always created
  166.                 GetTIFFHdrInfo(theDocHndl,&theTiffStruct);
  167.                 error = GetTIFFIFDirectory(theDocHndl,&theTiffStruct);
  168.                 if (error == kTIFFNotSupported)
  169.                 {
  170.                     if (theTiffStruct.tiffCTabHndl)
  171.                         DisposeHandle((Handle)theTiffStruct.tiffCTabHndl);
  172.                     CleanLoadAbort(theDocHndl);
  173.                     DisplayAlert (rGenWarning, rFileIOMessages, iTiffNotSupported);
  174.                     return error;
  175.                 }
  176.                 // cannot at present support TIFF files that aren't 8 or 32 bit
  177.                 switch (theTiffStruct.bitDepth)
  178.                 {
  179.                     case 8:
  180.                         (**theDocHndl).theImageWorld = 
  181.                             CreateOffscreen(theTiffStruct.tiffCTabHndl,
  182.                                             theTiffStruct.xImageSize,
  183.                                             theTiffStruct.yImageSize,
  184.                                             theTiffStruct.bitDepth,kNoFlags);
  185.                         if ((**theDocHndl).theImageWorld == nil)
  186.                         {
  187.                             DisposeHandle((Handle)theDocHndl);
  188.                             return kFailMakeGWorld;
  189.                         }
  190.                     break;
  191.                     case 32:
  192.                         (**theDocHndl).theImageWorld = 
  193.                             CreateOffscreen(nil,
  194.                                             theTiffStruct.xImageSize,
  195.                                             theTiffStruct.yImageSize,
  196.                                             theTiffStruct.bitDepth,kNoFlags);
  197.                         if ((**theDocHndl).theImageWorld == nil)
  198.                         {
  199.                             DisposeHandle((Handle)theDocHndl);
  200.                             return kFailMakeGWorld;
  201.                         }
  202.                     break;
  203.                     default:
  204.                         DisplayAlert (rGenWarning,rErrMessages,iNoSupportBitDepth);
  205.                         return kBitDepthErr;
  206.                     break;
  207.                 }
  208.                 // Fill in image coord sizes and bit depth to document structure
  209.                 (**theDocHndl).theImageXSize = theTiffStruct.xImageSize;
  210.                 (**theDocHndl).theImageYSize = theTiffStruct.yImageSize;
  211.                 (**theDocHndl).theImageDepth = theTiffStruct.bitDepth;
  212.                 // Perform TIFF file parse directly into GWorld referenced from document structure
  213.                 error = LoadTiffToGWorld (theDocHndl,&theTiffStruct,theTiffStruct.bitDepth);
  214.                 if (error)
  215.                 {
  216.                     DisplayAlert (rGenAlert,0,0);
  217.                     return error;
  218.                 }
  219.                 SetUndoItemText(kCannotUndo);
  220.                 error = CreateImageWindow (theDocHndl);
  221.                 if (error == kDefaultAppError)
  222.                 {
  223.                     DisplayAlert (rGenAlert,0,0);
  224.                     return error;
  225.                 }
  226.                 // Dispose of Tiff struct color table handle 
  227.                 if (theTiffStruct.tiffCTabHndl)
  228.                     DisposeHandle((Handle)theTiffStruct.tiffCTabHndl);
  229.                 error = AddDocNameToMenu(theDocHndl);
  230.                 if (error)
  231.                     DisplayAlert (rGenAlert,0,0);
  232.                 else
  233.                     return noErr;
  234.             break;
  235.             case ('PICT'):                                // PICT type
  236.                 // Set up document structure to defaults for image type
  237.                 (**theDocHndl).theFileType = PictType;
  238.                 (**theDocHndl).theImageChanged = false;
  239.                 (**theDocHndl).theColorsPalette = nil;
  240.                 (**theDocHndl).theImageWorld = nil;
  241.                 (**theDocHndl).theVScrollBar = nil;
  242.                 (**theDocHndl).theHScrollBar = nil;
  243.                 (**theDocHndl).theUndoState = kCannotUndo;
  244.                 (**theDocHndl).hasUndoTemp = false;
  245.                 (**theDocHndl).hasRedoTemp = false;
  246.                 // Load PICT file into PicHandle structure before placing in GWorld
  247.                 thePictHndl = LoadPictImageFile(theDocHndl);
  248.                 if (!thePictHndl)
  249.                 {
  250.                     DisposeHandle((Handle)theDocHndl);
  251.                     return kDefaultAppError;
  252.                 }
  253.                 // test if minimal temp memory free available. If none available GetPictInfo() fails.
  254.                 if (TempFreeMem() < kMinLowMem)
  255.                 {
  256.                     DisplayAlert(rGenWarning,rErrMessages,iLowTempMem);
  257.                     DisposeHandle((Handle)theDocHndl);
  258.                     return kLowMemWarning;
  259.                 }
  260.                 error = GetPictInfo (thePictHndl, &thePictInfo, returnColorTable,256,systemMethod,0);
  261.                 // Fill in image coord sizes and bit depth to document structure
  262.                 (**theDocHndl).theImageXSize = thePictInfo.sourceRect.right - thePictInfo.sourceRect.left;
  263.                 (**theDocHndl).theImageYSize = thePictInfo.sourceRect.bottom - thePictInfo.sourceRect.top;
  264.                 (**theDocHndl).theImageDepth = thePictInfo.depth;
  265.                 // Create window document's GWorld structure and draw loaded Pict image into it.
  266.                 if (!error && thePictInfo.depth <= 8)
  267.                     (**theDocHndl).theImageWorld = 
  268.                         CreateOffscreen(thePictInfo.theColorTable,
  269.                                         (**theDocHndl).theImageXSize,
  270.                                         (**theDocHndl).theImageYSize,
  271.                                         (**theDocHndl).theImageDepth,kNoFlags);
  272.                 else
  273.                     (**theDocHndl).theImageWorld = 
  274.                         CreateOffscreen(nil,
  275.                                         (**theDocHndl).theImageXSize,
  276.                                         (**theDocHndl).theImageYSize,
  277.                                         (**theDocHndl).theImageDepth,kNoFlags);
  278.                 
  279.                 if ((**theDocHndl).theImageWorld == nil)
  280.                 {
  281.                     DisposeHandle((Handle)theDocHndl);        // dispose image document
  282.                     DisposeHandle((Handle)thePictHndl);        // dispose picHandle
  283.                     return kFailMakeGWorld;
  284.                 }
  285.                 error = DrawPictToGWorld (theDocHndl,thePictHndl);
  286.                 SetUndoItemText(kCannotUndo);
  287.                 error = CreateImageWindow (theDocHndl);
  288.                 if (error == kDefaultAppError)
  289.                 {
  290.                     DisplayAlert (rGenAlert,0,0);
  291.                     return error;
  292.                 }
  293.                 error = AddDocNameToMenu(theDocHndl);
  294.                 if (error)
  295.                     DisplayAlert (rGenAlert,0,0);
  296.                 else
  297.                     return noErr;
  298.             break;
  299.             case ('qdgx'):
  300.                 // QuickDraw GX file load function is not yet supported in this release. 
  301.                 // It will be included in a future release.
  302.                 SetUndoItemText(kCannotUndo);
  303.                 DisplayAlert (rGenAlert,rErrMessages,iNotImplemented);
  304.                 return kNotSupported;
  305.             break;
  306.         }
  307.     }
  308.     return kFileLoadAbortErr;
  309. }
  310.  
  311.  
  312. /****    CustomGetFile    dialog file hook func    ****/
  313.  
  314. // This function handles user interaction of the custom dialog items added to the
  315. // CustomGetFile dialog and ignores all other items which are returned and processed
  316. // by the standard internal function.
  317.  
  318. #pragma segment fileSys
  319. pascal short    CustomGetFileHook(short item,DialogPtr theDlogPtr,void* theData)
  320. {
  321.     Handle                theHandle;
  322.     Rect                theRect;
  323.     short                theType,
  324.                         ignored;
  325.     
  326.     switch (item)    
  327.     {
  328.         case sfHookFirstCall:
  329.             GetDItem(theDlogPtr,kLoadFilePopUpItem,&theType,&theHandle,&theRect);
  330.             switch (gLoadFileType)
  331.             {
  332.                 case 'TIFF':
  333.                     theType = iTiffType;
  334.                 break;
  335.                 case 'PICT':
  336.                     theType = iPictType;
  337.                 break;
  338.                 case 'qdgx':
  339.                     theType = iGXType;
  340.                 break;
  341.                 default:
  342.                     theType = iAllFiles;
  343.                 break;
  344.             }
  345.             SetCtlValue((ControlHandle)theHandle,theType);
  346.             return sfHookNullEvent;
  347.         break;
  348.         case kLoadFilePopUpItem:
  349.             GetDItem(theDlogPtr,item,&ignored,&theHandle,&theRect);
  350.             theType = GetCtlValue((ControlHandle)theHandle);
  351.             switch (theType)
  352.             {
  353.                 case iTiffType:
  354.                     gLoadFileType = 'TIFF';
  355.                     item = sfHookRebuildList;
  356.                 break;
  357.                 case iPictType:
  358.                     gLoadFileType = 'PICT';
  359.                     item = sfHookRebuildList;
  360.                 break;
  361.                 case iGXType:
  362.                     gLoadFileType = 'qdgx';
  363.                     item = sfHookRebuildList;
  364.                 break;
  365.                 case iAllFiles:
  366.                     gLoadFileType = '????';
  367.                     item = sfHookRebuildList;
  368.                 break;
  369.             }
  370.             return item;
  371.         break;
  372.     }
  373.     return item;
  374. }    
  375.  
  376.  
  377. /****    basic CustomGetFile filter function    ****/
  378.  
  379. // File filter function is used by CustomGetFile() to restrict the
  380. // display of files and folders to supported image file types and visible folders.
  381.  
  382. #pragma segment fileSys
  383. pascal Boolean    CustomFileDlogFilter(CInfoPBPtr theParamBlok, Ptr theDataPtr)
  384. {
  385.     Boolean        notDisplayed = true;
  386.     
  387.     switch (theParamBlok->hFileInfo.ioFlFndrInfo.fdType)
  388.     {
  389.         case 'TIFF':
  390.             if (gLoadFileType == 'TIFF' || gLoadFileType == '????')
  391.                 notDisplayed = false;
  392.         break;
  393.         case 'PICT':
  394.             if (gLoadFileType == 'PICT' || gLoadFileType == '????')
  395.                 notDisplayed = false;
  396.         break;
  397.         case 'qdgx':
  398.             if (gLoadFileType == 'qdgx' || gLoadFileType == '????')
  399.                 notDisplayed = false;
  400.         break;
  401.         default:
  402.             if ((theParamBlok->dirInfo.ioFlAttrib & kFolderBit) && 
  403.                 !(theParamBlok->hFileInfo.ioFlFndrInfo.fdFlags & kFileVisibleBit))
  404.                     notDisplayed = false;
  405.         break;
  406.     }
  407.     return    notDisplayed;
  408. }
  409.  
  410.  
  411. /****    retrieve TIFF image header information    ****/
  412.  
  413. // Retrieve TIFF file header information and parse. Used to calculate file information
  414. // when reading in TIFF directory data.
  415.  
  416. #pragma segment fileSys
  417. void    GetTIFFHdrInfo(ImageDocHndl theDocHndl, TiffInfo *theTiffHeader)
  418. {
  419.     long                fileLen;
  420.     StandardFileReply     theFileSpec = (**theDocHndl).theImageFileReply;    // use local as FSpOpenDF returns param in spec
  421.     char                headerStore[8];
  422.     
  423.     FSpOpenDF(&theFileSpec.sfFile,fsRdPerm,&theFileSpec.sfFile.vRefNum); // open file
  424.     // Get size of file storage of TIFF header and read in TIFF header info
  425.     fileLen = sizeof(headerStore);                    
  426.     FSRead(theFileSpec.sfFile.vRefNum,&fileLen,headerStore);     
  427.     FSClose(theFileSpec.sfFile.vRefNum);
  428.     // copy header information to data structure
  429.     BlockMoveData(headerStore,&theTiffHeader->byteOrder,2);
  430.     BlockMoveData(&headerStore[2],&theTiffHeader->version,2);
  431.     if (theTiffHeader->byteOrder == IntlFormat)
  432.         theTiffHeader->version = SwapByteOrder(theTiffHeader->version,2);
  433.     BlockMoveData(&headerStore[4],&theTiffHeader->offsetToIFD,4);
  434.     if (theTiffHeader->byteOrder == IntlFormat)
  435.         theTiffHeader->offsetToIFD = SwapByteOrder(theTiffHeader->offsetToIFD,4);
  436.     return;
  437. }
  438.  
  439.  
  440. /****    Retrieve TIFF format image file directory info    ****/
  441.  
  442. // Function to parse the TIFF image file and load the image
  443. // data directly into a previously created GWorld PixMap.
  444. // If the TIFF file is an indexed image the color table information
  445. // is used to manually create a Color Table
  446.  
  447. #pragma segment fileSys
  448. OSErr    GetTIFFIFDirectory(ImageDocHndl theDocHndl, TiffInfo *theTiffHeader)
  449. {
  450.     long                fileLen,
  451.                         tempDecode,            // temporary decoder storage
  452.                         myOldFilePos,
  453.                         cTabSize;
  454.     StandardFileReply    theFileSpec = (**theDocHndl).theImageFileReply; // use local as FSpOpen returns param in spec
  455.     char                iFDcounter[2],        // number of IFD entries
  456.                         iFDStore[12],        // IFD field entry
  457.                         iFDOffset[4];        // offset to next IFD
  458.     short                entriesLeft,        // IFD's to process
  459.                         numberColors,
  460.                         colorValue,
  461.                         countStep,
  462.                         count;
  463.     OSErr                error = noErr,
  464.                         myFileErr;
  465.     Boolean                isIntFormat = false;
  466.     
  467.     if (theTiffHeader->byteOrder == IntlFormat)
  468.         isIntFormat = true;
  469.     FSpOpenDF(&theFileSpec.sfFile,fsRdPerm,&theFileSpec.sfFile.vRefNum);
  470.     SetFPos(theFileSpec.sfFile.vRefNum,fsFromStart,theTiffHeader->offsetToIFD);
  471.     fileLen = sizeof(iFDcounter);
  472.     FSRead(theFileSpec.sfFile.vRefNum,&fileLen,iFDcounter);
  473.     BlockMoveData(iFDcounter,&entriesLeft,2);
  474.     if (isIntFormat)
  475.         entriesLeft = SwapByteOrder(entriesLeft,2);
  476.     fileLen = sizeof(iFDStore);
  477.     do{
  478.         do{
  479.             myFileErr = FSRead(theFileSpec.sfFile.vRefNum,&fileLen,iFDStore);    // get pattern header info
  480.             if (myFileErr)
  481.                 DebugStr("\pError in reading IFDirectory");
  482.             BlockMoveData(iFDStore,&tempDecode,2);
  483.             tempDecode=tempDecode>>16;
  484.             if (isIntFormat)
  485.                 tempDecode = SwapByteOrder(tempDecode,2);
  486.             switch (tempDecode)
  487.             {
  488.                 case 0xFE:            // get image subfile type
  489.                     BlockMoveData(&iFDStore[8],&tempDecode,4);
  490.                     if (tempDecode!=0)
  491.                         DebugStr("\pIFD new subfile type not supported"); 
  492.                 break;
  493.                 case 0x100:            // image width
  494.                     BlockMoveData(&iFDStore[2],&tempDecode,2);
  495.                     tempDecode=tempDecode>>16;
  496.                     if (isIntFormat)
  497.                         tempDecode = SwapByteOrder(tempDecode,2);
  498.                     if (tempDecode==3)
  499.                     {
  500.                         BlockMoveData(&iFDStore[8],&tempDecode,2);
  501.                         tempDecode=tempDecode>>16;
  502.                         if (isIntFormat)
  503.                             tempDecode = SwapByteOrder(tempDecode,2);
  504.                     }
  505.                     else     
  506.                     {
  507.                         BlockMoveData(&iFDStore[8],&tempDecode,4);
  508.                         if (isIntFormat)
  509.                             tempDecode = SwapByteOrder(tempDecode,4);
  510.                     }
  511.                     theTiffHeader->xImageSize = tempDecode;
  512.                 break;
  513.                 case 0x101:            // image length
  514.                     BlockMoveData(&iFDStore[2],&tempDecode,2);
  515.                     tempDecode=tempDecode>>16;
  516.                     if (isIntFormat)
  517.                         tempDecode = SwapByteOrder(tempDecode,2);
  518.                     if (tempDecode==3)
  519.                     {
  520.                         BlockMoveData(&iFDStore[8],&tempDecode,2);
  521.                         tempDecode=tempDecode>>16;
  522.                         if (isIntFormat)
  523.                             tempDecode = SwapByteOrder(tempDecode,2);
  524.                     }
  525.                     else     
  526.                     {
  527.                         BlockMoveData(&iFDStore[8],&tempDecode,4);
  528.                         if (isIntFormat)
  529.                             tempDecode = SwapByteOrder(tempDecode,4);
  530.                     }
  531.                     theTiffHeader->yImageSize = tempDecode;
  532.                 break;
  533.                 case 0x102:            // bits per sample
  534.                     BlockMoveData(&iFDStore[8],&tempDecode,2);
  535.                     tempDecode=tempDecode>>16;
  536.                     if (isIntFormat)
  537.                         tempDecode = SwapByteOrder(tempDecode,2);
  538.                     theTiffHeader->bitDepth = tempDecode;
  539.                 break;
  540.                 case 0x103:            // image compression NOT SUPPORTED YET!!
  541.                     BlockMoveData(&iFDStore[8],&tempDecode,2);
  542.                     tempDecode=tempDecode>>16;
  543.                     if (isIntFormat)
  544.                         tempDecode = SwapByteOrder(tempDecode,2);
  545.                     theTiffHeader->compressionType = tempDecode;
  546.                     if (tempDecode != 1)
  547.                         return kTIFFNotSupported;
  548.                 break;
  549.                 case 0x106:            // Photometricinterpretation
  550.                     BlockMoveData(&iFDStore[8],&tempDecode,2);
  551.                     tempDecode=tempDecode>>16;
  552.                     if (isIntFormat)
  553.                         tempDecode = SwapByteOrder(tempDecode,2);
  554.                     theTiffHeader->PhotoInterpret = tempDecode;
  555.                     if (tempDecode > 3)
  556.                         return kTIFFNotSupported;
  557.                 break;
  558.                 case 0x111:            // strip offsets for one strip. Is offset to data
  559.                     BlockMoveData(&iFDStore[2],&tempDecode,2);
  560.                     tempDecode=tempDecode>>16;
  561.                     if (tempDecode==3)
  562.                     {
  563.                         BlockMoveData(&iFDStore[8],&tempDecode,2);
  564.                         tempDecode=tempDecode>>16;
  565.                         if (isIntFormat)
  566.                             tempDecode = SwapByteOrder(tempDecode,2);
  567.                     }
  568.                     else     
  569.                     {
  570.                         BlockMoveData(&iFDStore[8],&tempDecode,4);
  571.                         if (isIntFormat)
  572.                             tempDecode = SwapByteOrder(tempDecode,4);
  573.                     }
  574.                     theTiffHeader->imageOffset = tempDecode;    // offset to image strip
  575.                 break;
  576.                 case 0x115:            // samples per pixel 1 for palette, 3 for direct
  577.                     BlockMoveData(&iFDStore[8],&tempDecode,2);
  578.                     tempDecode=tempDecode>>16;
  579.                     if (isIntFormat)
  580.                         tempDecode = SwapByteOrder(tempDecode,2);
  581.                     theTiffHeader->bitDepth = tempDecode*8;
  582.                     if (theTiffHeader->bitDepth == 24)
  583.                         theTiffHeader->bitDepth = 32;    // amend to 32 bpp to correctly create GWorld 
  584.                     if (theTiffHeader->PhotoInterpret < 2)
  585.                     {
  586.                         if (theTiffHeader->bitDepth == 8)    // 8 Bit Greyscale image
  587.                         {
  588.                             numberColors = 256;            // number of entries in palette
  589.                             countStep = 1;
  590.                         }
  591.                         if (theTiffHeader->bitDepth == 4)    // 4 Bit Greyscale image
  592.                         {
  593.                             numberColors = 16;
  594.                             countStep = 16;
  595.                         }
  596.                         // Manually create the Color Table from TIFF file information
  597.                         cTabSize = sizeof(ColorTable)+(sizeof(ColorSpec)*(numberColors-1));
  598.                         theTiffHeader->tiffCTabHndl = (CTabHandle) NewHandle(cTabSize);
  599.                         if (theTiffHeader->tiffCTabHndl == nil || MemError())
  600.                         {
  601.                             return kDefaultAppError;
  602.                         }
  603.                         (**theTiffHeader->tiffCTabHndl).ctFlags = 0;
  604.                         (**theTiffHeader->tiffCTabHndl).ctSize = numberColors-1;
  605.                         switch (theTiffHeader->PhotoInterpret)
  606.                         {
  607.                             case 0:
  608.                                 for (count=0;count<numberColors;count+=countStep)
  609.                                 {
  610.                                     colorValue = (255 - count) << 8;
  611.                                     (**theTiffHeader->tiffCTabHndl).ctTable[count].value = count;
  612.                                     (**theTiffHeader->tiffCTabHndl).ctTable[count].rgb.red = colorValue;        // red component
  613.                                     (**theTiffHeader->tiffCTabHndl).ctTable[count].rgb.green = colorValue;        // green component
  614.                                     (**theTiffHeader->tiffCTabHndl).ctTable[count].rgb.blue = colorValue;        // blue component
  615.                                 }
  616.                             break;
  617.                             
  618.                             case 1:
  619.                                 for (count=0;count<numberColors;count+=countStep)
  620.                                 {
  621.                                     
  622.                                     colorValue = count << 8;
  623.                                     (**theTiffHeader->tiffCTabHndl).ctTable[count].value = count;
  624.                                     (**theTiffHeader->tiffCTabHndl).ctTable[count].rgb.red = colorValue;    // red component
  625.                                     (**theTiffHeader->tiffCTabHndl).ctTable[count].rgb.green = colorValue;    // green component
  626.                                     (**theTiffHeader->tiffCTabHndl).ctTable[count].rgb.blue = colorValue;    // blue component
  627.                                 }
  628.                             break;
  629.                         }
  630.                         CTabChanged(theTiffHeader->tiffCTabHndl);
  631.                     }
  632.                 break;
  633.                 case 0x116:            // number of rows per image strip
  634.                     BlockMoveData(&iFDStore[2],&tempDecode,2);
  635.                     tempDecode = tempDecode>>16;
  636.                     if (isIntFormat)
  637.                         tempDecode = SwapByteOrder(tempDecode,2);
  638.                     if (tempDecode == 3)
  639.                     {
  640.                         BlockMoveData(&iFDStore[8],&tempDecode,2);
  641.                         tempDecode=tempDecode>>16;
  642.                         if (isIntFormat)
  643.                             tempDecode = SwapByteOrder(tempDecode,2);
  644.                     }
  645.                     else
  646.                     {
  647.                         BlockMoveData(&iFDStore[8],&tempDecode,4);
  648.                         if (isIntFormat)
  649.                             tempDecode = SwapByteOrder(tempDecode,4);
  650.                     }
  651.                     theTiffHeader->rowStrip = tempDecode;
  652.                 break;
  653.                 case 0x11C:
  654.                     BlockMoveData(&iFDStore[8],&tempDecode,2);
  655.                     if (isIntFormat)
  656.                         tempDecode = SwapByteOrder(tempDecode,2);
  657.                     theTiffHeader->PlanarConfig = tempDecode>>16;
  658.                 break;
  659.                 case 0x140:            // image clut for palette images
  660.                     if (theTiffHeader->bitDepth == 8)    // 8 Bit palette image
  661.                         numberColors = 256;        // number of entries in palette
  662.                     if (theTiffHeader->bitDepth == 4)    // 4 Bit palette image
  663.                         numberColors = 16;
  664.                     cTabSize = sizeof(ColorTable)+(sizeof(ColorSpec)*(numberColors-1));
  665.                     theTiffHeader->tiffCTabHndl = (CTabHandle) NewHandle(cTabSize);
  666.                     if (theTiffHeader->tiffCTabHndl==nil)
  667.                     {
  668.                         return kDefaultAppError;
  669.                     }
  670.                     (**theTiffHeader->tiffCTabHndl).ctFlags = 0;
  671.                     (**theTiffHeader->tiffCTabHndl).ctSize = numberColors-1;
  672.                     BlockMoveData(&iFDStore[8],&tempDecode,4);
  673.                     if (isIntFormat)
  674.                         tempDecode = SwapByteOrder(tempDecode,4);
  675.                     GetFPos(theFileSpec.sfFile.vRefNum,&myOldFilePos);    // get old file position
  676.                     SetFPos(theFileSpec.sfFile.vRefNum,fsFromStart,tempDecode); // set new file pos
  677.                     fileLen = sizeof(short);
  678.                     for (count=0;count<numberColors;count++)
  679.                     {
  680.                         (**theTiffHeader->tiffCTabHndl).ctTable[count].value = count;
  681.                         FSRead(theFileSpec.sfFile.vRefNum,&fileLen,&tempDecode);
  682.                         tempDecode = tempDecode>>16;
  683.                         if (isIntFormat)
  684.                             tempDecode = SwapByteOrder(tempDecode,2);
  685.                         (**theTiffHeader->tiffCTabHndl).ctTable[count].rgb.red = tempDecode;        // red component
  686.                     }
  687.                     for (count=0;count<numberColors;count++)
  688.                     {
  689.                         FSRead(theFileSpec.sfFile.vRefNum,&fileLen,&tempDecode);
  690.                         tempDecode = tempDecode>>16;
  691.                         if (isIntFormat)
  692.                             tempDecode = SwapByteOrder(tempDecode,2);
  693.                         (**theTiffHeader->tiffCTabHndl).ctTable[count].rgb.green = tempDecode;        // green component
  694.                     }
  695.                     for (count=0;count<numberColors;count++)
  696.                     {
  697.                         FSRead(theFileSpec.sfFile.vRefNum,&fileLen,&tempDecode);
  698.                         tempDecode = tempDecode>>16;
  699.                         if (isIntFormat)
  700.                             tempDecode = SwapByteOrder(tempDecode,2);
  701.                         (**theTiffHeader->tiffCTabHndl).ctTable[count].rgb.blue = tempDecode;        // blue component
  702.                     }
  703.                     CTabChanged(theTiffHeader->tiffCTabHndl);
  704.                     SetFPos(theFileSpec.sfFile.vRefNum,fsFromStart,myOldFilePos);
  705.                 break;
  706.                 case 0x153:    // Sample Format tag
  707.                     BlockMoveData(&iFDStore[8],&tempDecode,2);
  708.                     tempDecode=tempDecode>>16;
  709.                     if (isIntFormat)
  710.                         tempDecode = SwapByteOrder(tempDecode,2);
  711.                     if (tempDecode != 1)
  712.                         return kTIFFNotSupported;
  713.                 break;
  714.                 case 0x142:    // handle unsupported tags which could cause incorrect image display
  715.                 case 0x143:
  716.                 case 0x152:
  717.                     return kTIFFNotSupported;
  718.                 break;
  719.             }    
  720.             entriesLeft--;
  721.         } while (entriesLeft!=0);                // read all tags
  722.         // multi IFD stuff Needs to be expanded to support 
  723.         fileLen = sizeof(iFDOffset);
  724.         FSRead(theFileSpec.sfFile.vRefNum,&fileLen,iFDOffset);// get pattern header info
  725.         BlockMoveData(iFDOffset,&theTiffHeader->offsetToIFD,4);
  726.         if (isIntFormat)
  727.             tempDecode = SwapByteOrder(tempDecode,4);
  728.         SetFPos(theFileSpec.sfFile.vRefNum,fsFromStart,theTiffHeader->offsetToIFD);
  729.         theTiffHeader->offsetToIFD = 0;            // force to zero as don't support multiple images in file
  730.     } while (theTiffHeader->offsetToIFD!=0);    // read next IFD if present
  731.     FSClose(theFileSpec.sfFile.vRefNum);         // close open file
  732.     return    error;
  733. }
  734.  
  735.  
  736. /****        Draw the TIFF image data directly into the offscreen pixmap    ****/
  737.  
  738. #pragma segment fileSys
  739. OSErr LoadTiffToGWorld (ImageDocHndl theImageDocHndl, TiffInfoPtr theTiffInfo, short bitDepth)
  740. {
  741.     PixMapHandle        thePixMapHndl = nil;
  742.     CursHandle            watchCrsr;
  743.     Ptr                    imageLinePtr = nil,
  744.                         theLinePosPtr;
  745.     float                theBarStepValue,
  746.                         theBarValue;
  747.     long                theFileLen,
  748.                         imageLeft = theTiffInfo->rowStrip,
  749.                         imageLineStart,
  750.                         spinCounter = 0;
  751.     StandardFileReply    theFileSpec = (**theImageDocHndl).theImageFileReply; // use local as FSpOpen returns param in spec
  752.     OSErr                error = noErr;
  753.     short                theGWrowBytes,
  754.                         xCount,
  755.                         imageWidth;
  756.     
  757.     thePixMapHndl = GetGWorldPixMap((*theImageDocHndl)->theImageWorld);
  758.     if (PixMap32Bit(thePixMapHndl))
  759.         SaveSetMMUMode(true);
  760.     if (!LockPixels(thePixMapHndl))
  761.         error = kFailedLockPixels;
  762.     if (!error)
  763.     {
  764.         theBarStepValue = (float)kProgressSteps/(*theImageDocHndl)->theImageYSize; 
  765.         theBarValue = theBarStepValue;    //    intialise progress bar value
  766.         error = FSpOpenDF(&theFileSpec.sfFile,fsRdPerm,&theFileSpec.sfFile.vRefNum);
  767.         error |= SetFPos(theFileSpec.sfFile.vRefNum,fsFromStart,theTiffInfo->imageOffset);
  768.         if (!error) 
  769.         {
  770.             imageLinePtr = GetPixBaseAddr(thePixMapHndl);    // base addr of GWorld
  771.             imageLineStart = (long)imageLinePtr;
  772.             theGWrowBytes = (**thePixMapHndl).rowBytes & 0x3FFF;
  773.             // Display the progress bar dialog to provide feedback on load operation.
  774.             DisplayProgressBarDlog(kDisplayProgressWindow, 0 , rProgressMessages, iLoading);
  775.             // Read in imaga data from file into Pixmap
  776.             switch (bitDepth)
  777.             {
  778.                 case 8:
  779.                     theFileLen = (**thePixMapHndl).bounds.right - (**thePixMapHndl).bounds.left;
  780.                     watchCrsr = GetCursor(watchCursor);
  781.                     SetCursor(*watchCrsr);
  782.                     do{
  783.                         FSRead(theFileSpec.sfFile.vRefNum,&theFileLen,imageLinePtr);    // get count
  784.                         imageLinePtr+=theGWrowBytes;
  785.                         imageLeft--;
  786.                         theBarValue += theBarStepValue;
  787.                         DisplayProgressBarDlog(kUpdateProgressWindow, (short)theBarValue, 0, 0);
  788.                         RotateCursor(spinCounter+=8);
  789.                     } while (imageLeft);
  790.                     SetCursor(&qd.arrow);
  791.                 break;
  792.                 case 16:
  793.                     DebugStr("\p16 bit color depth not supported");
  794.                 break;
  795.                 case 32:
  796.                     theFileLen = 3;
  797.                     imageWidth = (**thePixMapHndl).bounds.right - (**thePixMapHndl).bounds.left;
  798.                     watchCrsr = GetCursor(watchCursor);
  799.                     SetCursor(*watchCrsr);
  800.                     do{
  801.                         theLinePosPtr = imageLinePtr;
  802.                         theLinePosPtr++;
  803.                         for (xCount = 0;xCount<imageWidth;xCount++)
  804.                         {
  805.                             FSRead(theFileSpec.sfFile.vRefNum,&theFileLen,theLinePosPtr);
  806.                             theLinePosPtr+=4;
  807.                         }
  808.                         imageLinePtr+=theGWrowBytes;
  809.                         imageLeft--;
  810.                         theBarValue += theBarStepValue;
  811.                         DisplayProgressBarDlog(kUpdateProgressWindow, (short)theBarValue, 0, 0);
  812.                         RotateCursor(spinCounter+=8);
  813.                     } while (imageLeft);
  814.                     SetCursor(&qd.arrow);
  815.                 break;
  816.             }
  817.             UnlockPixels(thePixMapHndl);
  818.             DisplayProgressBarDlog(kDisposeProgressWindow,0,0,0);
  819.         }
  820.         else
  821.             DebugStr("\pError opening and setting file offset in LoadTiffToGWorld");
  822.     }
  823.     SaveSetMMUMode(false);
  824.     return error;
  825. }
  826.  
  827.  
  828. /****    Swap the byte order between little and big endian formats    ****/
  829.  
  830. #pragma segment fileSys
  831. long    SwapByteOrder(long    theData,short    theDataLength)
  832. {
  833.     long    tempStore,
  834.             tempStore2,
  835.             tempStore3,
  836.             tempStore4;
  837.     
  838.     switch(theDataLength)
  839.     {
  840.         case (2):
  841.             tempStore = theData << 8;
  842.             tempStore = tempStore & 0x0000FF00;
  843.             tempStore2 = theData >> 8;
  844.             tempStore2 = tempStore2 & 0x000000FF;
  845.             theData = tempStore + tempStore2;
  846.         break;
  847.         case (4):
  848.             tempStore = theData << 24;
  849.             tempStore = tempStore & 0xFF000000;
  850.             tempStore2 = theData << 8;
  851.             tempStore2 = tempStore2 & 0x00FF0000;
  852.             tempStore3 = theData >> 8;
  853.             tempStore3 = tempStore3 & 0x0000FF00;
  854.             tempStore4 = theData >> 24;
  855.             tempStore4 = tempStore4 & 0x000000FF;
  856.             theData = tempStore + tempStore2 + tempStore3 + tempStore4;
  857.         break;
  858.     }
  859.     return theData;
  860. }
  861.  
  862.  
  863. /****    Load PICT file into PicHandle    ****/
  864.  
  865. // Basic PICT file load function that takes a PICT file
  866. // and returns the loaded image in a PicHandle structure.
  867. // If an error occurs nil is returned to indicate load problem.
  868.  
  869. #pragma segment fileSys
  870. PicHandle    LoadPictImageFile(ImageDocHndl    theDocHndl)
  871. {
  872.     PicHandle            thePictHndl;
  873.     long                thePictFileSize;
  874.     StandardFileReply     theFileSpec = (**theDocHndl).theImageFileReply;
  875.     short                theFileRef;
  876.     OSErr                error = noErr;
  877.     
  878.     error = FSpOpenDF(&theFileSpec.sfFile, fsRdPerm, &theFileRef);
  879.     if (!error)
  880.     {
  881.         error = GetEOF(theFileRef, &thePictFileSize);
  882.         if(error)
  883.         {
  884.             FSClose(theFileSpec.sfFile.vRefNum);
  885.             return nil; 
  886.         }
  887.         if(SetFPos(theFileRef,fsFromStart,512))
  888.         {
  889.             FSClose(theFileRef);
  890.             return nil; 
  891.         }
  892.         thePictFileSize -= 512;    // Remove unwanted 512 byte header 
  893.         thePictHndl = (PicHandle)NewHandle(thePictFileSize);
  894.         if(thePictHndl == nil)
  895.         {
  896.             FSClose(theFileRef);
  897.             return nil;
  898.         }
  899.         HLock((Handle)thePictHndl);
  900.         error = FSRead(theFileRef,&thePictFileSize,(Ptr)*thePictHndl);
  901.         HUnlock((Handle)thePictHndl);
  902.         FSClose(theFileRef);
  903.         if(error)
  904.             return nil; 
  905.         return thePictHndl;
  906.     }
  907.     return nil;
  908. }
  909.  
  910.  
  911. /****    Draw PicHandle into GWorld PixMap    ****/
  912.  
  913. // Draw a PICT contained in a PicHandle into a GWorld 
  914. // attached to the passed document structure parameter
  915.  
  916. #pragma segment fileSys
  917. OSErr    DrawPictToGWorld (ImageDocHndl    theDocHndl,PicHandle    thePictHndl)
  918. {
  919.     PixMapHandle    theGWorldPMHndl;
  920.     GDHandle        oldGDHndl;
  921.     CGrafPtr        oldGWorld;
  922.     OSErr            error = noErr;
  923.     
  924.     GetGWorld(&oldGWorld, &oldGDHndl);
  925.     SetGWorld((**theDocHndl).theImageWorld, nil);
  926.     // Reset foreground and background colors to black and white
  927.     // so no colorisation effects occur.
  928.     RGBForeColor(&kRGBBlack);                            
  929.     RGBBackColor(&kRGBWhite);
  930.     theGWorldPMHndl = GetGWorldPixMap((**theDocHndl).theImageWorld);
  931.     LockPixels(theGWorldPMHndl);
  932.     EraseRect(&(**theDocHndl).theImageWorld->portRect);
  933.     // Reset the transfer mode
  934.     PenMode(srcCopy);                                    
  935.     // render the image into the offscreen buffer
  936.     DrawPicture(thePictHndl, &(**theDocHndl).theImageWorld->portRect);
  937.     UnlockPixels(theGWorldPMHndl);
  938.     SetGWorld(oldGWorld, oldGDHndl);
  939.     // dispose of unwanted picHandle structure
  940.     DisposeHandle((Handle)thePictHndl);
  941.     return    error;
  942. }
  943.  
  944.  
  945. /****    Save supported file types    ****/
  946.  
  947. // Main function to perform the saving of supported image file types.
  948.  
  949. #pragma segment fileSys
  950. OSErr    SaveSupportedImageFile(ImageDocHndl    theDocHndl)
  951. {
  952.     StandardFileReply    theSFReply;
  953.     DlgHookYDUPP        theDialogHookUPP;
  954.     Point                dlogPosition = {-1,-1};
  955.     OSErr                error = noErr;
  956.     
  957.     gSaveFileType = (*theDocHndl)->theFileType;
  958.     theDialogHookUPP = NewDlgHookYDProc(CustomPutFileHook);
  959.     CustomPutFile((ConstStr255Param)kNull_Str, (**theDocHndl).theImageFileReply.sfFile.name,
  960.                   &theSFReply, rCustomSaveDialog,dlogPosition, theDialogHookUPP,
  961.                   nil, nil, nil, nil);
  962.     DisposeRoutineDescriptor((UniversalProcPtr)theDialogHookUPP);
  963.     if (theSFReply.sfGood)
  964.     {
  965.         /****    Dispose Temp file if present    ****/
  966.         if ((*theDocHndl)->hasUndoTemp || (*theDocHndl)->hasRedoTemp)
  967.             RemoveTempFile(theDocHndl, true, true);
  968.         switch (gSaveFileType)
  969.         {
  970.             case TiffType:
  971.             break;
  972.             case PictType:
  973.                 if ( !(*theDocHndl)->isUsingQDGX )
  974.                 {
  975.                     error = SavePictImage(theDocHndl, &theSFReply);
  976.                     switch (error)
  977.                     {
  978.                         case kFailPictCompSave:
  979.                             DisplayAlert(rGenAlert,rFileIOMessages,iSaveCompPICTErr);
  980.                         break;
  981.                         case kFailPictUnCompSave:
  982.                             DisplayAlert(rGenAlert,rFileIOMessages,iSaveUnCompPICTErr);
  983.                         break;
  984.                         case kFailedLockPixels:
  985.                             DisplayAlert(rGenAlert,rQDMessages,iFailLockPixmap);
  986.                         break;
  987.                     }
  988.                 }
  989.             break;
  990.             case GXType:
  991.                 if ( (*theDocHndl)->isUsingQDGX )
  992.                 {
  993.                     error = SaveQdGxShape(theDocHndl, &theSFReply);
  994.                     if (error)
  995.                         DisplayAlert(rGenAlert,rFileIOMessages,iSaveQDGXErr);
  996.                 }
  997.             break;
  998.         }
  999.     }
  1000.     return error;
  1001. }
  1002.  
  1003.  
  1004. /****    CustomPutFile    dialog file hook function    ****/
  1005.  
  1006. #pragma segment fileSys
  1007. pascal short    CustomPutFileHook(short item,DialogPtr theDlogPtr,void* theData)
  1008. {
  1009.     Handle                theHandle;
  1010.     Rect                theRect;
  1011.     short                theType,
  1012.                         ignored;
  1013.     
  1014.     if (GetWRefCon((WindowPtr)theDlogPtr) != sfMainDialogRefCon)
  1015.         return item;
  1016.     switch (item)    
  1017.     {
  1018.         case sfHookFirstCall:
  1019.             GetDItem(theDlogPtr,kSaveFilePopUpItem,&theType,&theHandle,&theRect);
  1020.             switch (gSaveFileType)
  1021.             {
  1022.                 case TiffType:
  1023.                     theType = iSaveTiffType;
  1024.                 break;
  1025.                 case PictType:
  1026.                     theType = iSavePictType;
  1027.                 break;
  1028.                 case GXType:
  1029.                     theType = iSaveGXType;
  1030.                 break;
  1031.             }
  1032.             SetCtlValue((ControlHandle)theHandle,theType);
  1033.             return sfHookNullEvent;
  1034.         break;
  1035.         case kSaveFilePopUpItem:
  1036.             GetDItem(theDlogPtr,item,&ignored,&theHandle,&theRect);
  1037.             theType = GetCtlValue((ControlHandle)theHandle);
  1038.             switch (theType)
  1039.             {
  1040.                 case iSaveTiffType:
  1041.                     gSaveFileType = TiffType;
  1042.                 break;
  1043.                 case iSavePictType:
  1044.                     gSaveFileType = PictType;
  1045.                 break;
  1046.                 case iSaveGXType:
  1047.                     gSaveFileType = GXType;
  1048.                 break;
  1049.             }
  1050.             return sfHookNullEvent;
  1051.         break;
  1052.     }
  1053.     return item;
  1054. }    
  1055.  
  1056.  
  1057. /****    Save image as PICT file        ****/
  1058.  
  1059. #pragma segment fileSys
  1060. OSErr SavePictImage(ImageDocHndl theDocHndl, StandardFileReply* thePictFile)
  1061. {
  1062.     Handle                    compDataHndl;
  1063.     Ptr                        compDataPtr;
  1064.     ImageDescriptionHandle    compImageDescHndl = nil;
  1065.     PicHandle                theSavePict = nil;
  1066.     GDHandle                theGDevHndl;
  1067.     PixMapHandle            theSavePictPixMapHndl = nil;
  1068.     GWorldPtr                oldPort;
  1069.     long                    thePictLen,
  1070.                             emptyDataSize = 4,
  1071.                             emptyData = 0x00000000,
  1072.                             maxCompSize = 0;
  1073.     CodecQ                    compQuality;
  1074.     Rect                    thePortRect;
  1075.     OpenCPicParams            thePictParams;
  1076.     OSErr                    error = noErr,
  1077.                             fileErr = noErr;
  1078.     short                    fileRefNum,
  1079.                             compressionSetting,
  1080.                             count;    
  1081.     
  1082.     GetGWorld(&oldPort,&theGDevHndl);
  1083.     thePortRect = (**theDocHndl).theImageWorld->portRect;
  1084.     theSavePictPixMapHndl = GetGWorldPixMap((**theDocHndl).theImageWorld);
  1085.     if (PixMap32Bit(theSavePictPixMapHndl))
  1086.         SaveSetMMUMode(true);
  1087.     if (LockPixels(theSavePictPixMapHndl))
  1088.     {
  1089.         /****    setup Color PICT paramaters    ****/
  1090.         thePictParams.srcRect = thePortRect;
  1091.         thePictParams.hRes = ff(72);
  1092.         thePictParams.vRes = ff(72);
  1093.         thePictParams.version = -2;
  1094.         thePictParams.reserved1 = 0;
  1095.         thePictParams.reserved2 = 0;
  1096.         // Display PICT compression setting dialog box
  1097.         compressionSetting = ProcessPictCompDlog();
  1098.         if (compressionSetting == kNoCompression)
  1099.         {
  1100.             
  1101.             // Create uncompressed PicHandle ready to save to disk.
  1102.             SetGWorld((**theDocHndl).theImageWorld,nil);
  1103.             theSavePict = OpenCPicture(&thePictParams);
  1104.             ClipRect (&thePortRect);
  1105.             CopyBits((BitMap*)(*theSavePictPixMapHndl),
  1106.                      (BitMap*)(*theSavePictPixMapHndl),
  1107.                      &thePortRect,
  1108.                      &thePortRect,srcCopy,nil);
  1109.             ClosePicture();
  1110.             SetGWorld(oldPort,theGDevHndl);
  1111.             UnlockPixels(theSavePictPixMapHndl);
  1112.         }
  1113.         else    
  1114.         {
  1115.             // Image compression selected. Compress image using chosen setting
  1116.             // and create PicHandle containing the compressed image ready to save to disk
  1117.             switch (compressionSetting)
  1118.             {
  1119.                 case kHighQuality:
  1120.                     compQuality = codecHighQuality;
  1121.                 break;
  1122.                 case kMediumQuality:
  1123.                     compQuality = codecNormalQuality;
  1124.                 break;
  1125.                 case kLowQuality:
  1126.                     compQuality = codecLowQuality;
  1127.                 break;
  1128.             }
  1129.             error = GetMaxCompressionSize(theSavePictPixMapHndl,
  1130.                                         &thePortRect,0,compQuality,
  1131.                                         'jpeg',anyCodec,&maxCompSize);
  1132.             if (error != noErr || maxCompSize == 0)
  1133.             {
  1134.                 UnlockPixels(theSavePictPixMapHndl);
  1135.                 SaveSetMMUMode(false);
  1136.                 return kDefaultAppError;
  1137.             }
  1138.             compImageDescHndl = (ImageDescriptionHandle) NewHandle(4);
  1139.             compDataHndl = NewHandle(maxCompSize);
  1140.             if (compImageDescHndl != nil && compDataHndl != nil)
  1141.             {
  1142.                 HLock(compDataHndl);
  1143.                 compDataPtr = StripAddress(*compDataHndl);
  1144.                 error = CompressImage (theSavePictPixMapHndl,&thePortRect,
  1145.                                        compQuality,'jpeg',compImageDescHndl,compDataPtr);
  1146.                 if (error != noErr)
  1147.                 {
  1148.                     RemoveOldSaveData(compImageDescHndl,compDataHndl,theSavePictPixMapHndl);
  1149.                     SaveSetMMUMode(false);
  1150.                     return kFailPictCompSave;
  1151.                 }
  1152.                 SetGWorld((**theDocHndl).theImageWorld,nil);
  1153.                 theSavePict = OpenCPicture(&thePictParams);
  1154.                 ClipRect (&thePortRect);
  1155.                 error = DecompressImage(compDataPtr, compImageDescHndl,
  1156.                                         theSavePictPixMapHndl,&thePortRect,
  1157.                                         &thePortRect, srcCopy, nil);
  1158.                 ClosePicture();
  1159.                 SetGWorld(oldPort,theGDevHndl);
  1160.                 RemoveOldSaveData(compImageDescHndl,compDataHndl,theSavePictPixMapHndl);
  1161.                 if (error)
  1162.                 {
  1163.                     if (theSavePict)
  1164.                         DisposeHandle((Handle)theSavePict);
  1165.                     SaveSetMMUMode(false);
  1166.                     return kFailPictCompSave;
  1167.                 }
  1168.             }
  1169.             else
  1170.             {
  1171.                 RemoveOldSaveData(compImageDescHndl,compDataHndl,theSavePictPixMapHndl);
  1172.                 SaveSetMMUMode(false);
  1173.                 return kFailPictCompSave;
  1174.             }
  1175.         }
  1176.     }
  1177.     else
  1178.         return kFailedLockPixels;    
  1179.     // Save image conatined in PicHandle structure to disk
  1180.     fileErr = FSpCreate(&thePictFile->sfFile,'ttxt','PICT',smSystemScript);
  1181.     if (!fileErr)
  1182.         fileErr = FSpOpenDF(&thePictFile->sfFile,fsRdWrPerm,&fileRefNum);
  1183.     if (!fileErr)
  1184.     {
  1185.         for (count = 0;count<128;count++)
  1186.             FSWrite(fileRefNum,&emptyDataSize,&emptyData);
  1187.         thePictLen = GetHandleSize((Handle)theSavePict);
  1188.         HLock((Handle)theSavePict);
  1189.         fileErr = FSWrite(fileRefNum,&thePictLen,*theSavePict);
  1190.         fileErr |= FSClose(fileRefNum);
  1191.         HUnlock((Handle)theSavePict);
  1192.         if (fileErr)
  1193.         {
  1194.             switch (compressionSetting)
  1195.             {
  1196.                 case kNoCompression:
  1197.                     error = kFailPictUnCompSave;
  1198.                 break;
  1199.                 default:
  1200.                     error = kFailPictCompSave;
  1201.                 break;
  1202.             }
  1203.         }
  1204.     }
  1205.     SaveSetMMUMode(false);
  1206.     if (theSavePict)
  1207.         DisposeHandle((Handle)theSavePict);
  1208.     return error;
  1209. }
  1210.  
  1211.  
  1212. /****    handle processing of the PICT file settings dialog    ****/
  1213.  
  1214. #pragma segment fileSys
  1215. short    ProcessPictCompDlog(void)
  1216. {
  1217.     Handle                theItemHandle;
  1218.     DialogPtr            theDialog = nil;
  1219.     ModalFilterUPP        theFilter = nil;
  1220.     GrafPtr                oldPort;
  1221.     Rect                theRect;
  1222.     short                theCompSetting = kNoCompression;
  1223.     short                theItem,
  1224.                         theNextItem,
  1225.                         theItemType,
  1226.                         count;
  1227.     
  1228.     GetPort(&oldPort);
  1229.     theDialog = GetNewDialog(rPictCompDialog,nil,((WindowPtr)-1L));
  1230.     SetPort(theDialog);
  1231.     if (!GetStdFilterProc(&theFilter))
  1232.         SetDialogDefaultItem(theDialog,1);
  1233.     GetDialogItem(theDialog,theCompSetting,&theItemType,&theItemHandle,&theRect);
  1234.     SetControlValue((ControlHandle)theItemHandle,1);
  1235.     do{
  1236.         ModalDialog(nil,&theItem);
  1237.         GetDialogItem(theDialog,theItem,&theItemType,&theItemHandle,&theRect);
  1238.         if (theItemType == kRadioButton)
  1239.         {
  1240.             for (count = kNoCompression; count<=kLowQuality; count++)
  1241.             {
  1242.                 GetDialogItem(theDialog,count,&theItemType,&theItemHandle,&theRect);
  1243.                 if (count == theItem)
  1244.                 {
  1245.                     SetControlValue((ControlHandle)theItemHandle,1);
  1246.                     theCompSetting = count;
  1247.                 }
  1248.                 else
  1249.                     SetControlValue((ControlHandle)theItemHandle,0);
  1250.             }
  1251.         }
  1252.     } while (theItem != kOkButton);
  1253.     DisposeDialog(theDialog);
  1254.     SetPort(oldPort);
  1255.     return    theCompSetting;
  1256. }
  1257.  
  1258.  
  1259. /****    Clean up after save file    ****/
  1260.  
  1261. #pragma segment fileSys
  1262. void    RemoveOldSaveData(ImageDescriptionHandle theImageDescH, Handle theDataH, PixMapHandle thePixMapHndl)
  1263. {
  1264.     UnlockPixels(thePixMapHndl);
  1265.     if (theImageDescH)
  1266.         DisposeHandle((Handle)theImageDescH);
  1267.     if (theDataH)
  1268.     {
  1269.         HUnlock(theDataH);
  1270.         DisposeHandle(theDataH);
  1271.     }
  1272. }
  1273.  
  1274.  
  1275. /****    convert QuickDraw GX shape to handle for saving to disk ****/
  1276.  
  1277. #pragma segment fileSys
  1278. void    SaveGXShapeToFile(gxShape theShape, gxFlattenFlag theFlags, short fileRefNum)
  1279. {
  1280.     UserGXSpool     dataBlock;
  1281.     
  1282.     dataBlock.spool.spoolProcedure = NewgxSpoolProc(FileSpoolProc);
  1283.     dataBlock.reference = fileRefNum;
  1284.     dataBlock.spool.buffer = nil;
  1285.     dataBlock.spool.bufferSize = 0;
  1286.     GXFlattenShape(theShape, theFlags, &dataBlock.spool);
  1287.     DisposeRoutineDescriptor(dataBlock.spool.spoolProcedure);
  1288. }
  1289.  
  1290.  
  1291. /****    Save flatten QD GX shape to disk    ****/
  1292.  
  1293. #pragma segment fileSys
  1294. OSErr    SaveQdGxShape(ImageDocHndl theDocHndl, StandardFileReply* thePictFile)
  1295. {
  1296.     OSErr        fileErr = noErr;
  1297.     short        theRefNum;
  1298.     
  1299.     if ((*theDocHndl)->theGXImageShape == nil)
  1300.         return kFailQDGXSave;
  1301.     fileErr = FSpCreate(&thePictFile->sfFile,(OSType)AppCreator,'qdgx',smSystemScript);
  1302.     if (!fileErr)
  1303.         fileErr = FSpOpenDF(&thePictFile->sfFile,fsRdWrPerm,&theRefNum);
  1304.     if (fileErr)
  1305.         DebugStr("\pFile error creating QDGX file for save operation");
  1306.     SaveGXShapeToFile((*theDocHndl)->theGXImageShape, 0,theRefNum);
  1307.     fileErr |= FSClose(theRefNum);
  1308.     if (fileErr)
  1309.         fileErr = kFailQDGXSave;
  1310.     return fileErr;
  1311. }
  1312.  
  1313.  
  1314. /**** QuickDraw GX shape to file Spooling function    ****/
  1315.  
  1316. #pragma segment fileSys
  1317. static long FileSpoolProc(gxSpoolCommand command, UserGXSpool *block)
  1318. {
  1319.    OSErr         error = noErr;
  1320.    
  1321.    switch (command)
  1322.    {
  1323.       case gxOpenReadSpool:
  1324.       break;
  1325.       case gxOpenWriteSpool:
  1326.       break;
  1327.       case gxReadSpool:
  1328.       break;
  1329.       case gxWriteSpool:
  1330.       {
  1331.          long count = block->spool.count;
  1332.          error = FSWrite(block->reference, &count, block->spool.buffer);
  1333.          if (error)
  1334.              DebugStr("\pFSWrite failed");
  1335.       }
  1336.       break;
  1337.       case gxCloseSpool:
  1338.       break;
  1339.       default:
  1340.          DebugStr("\punexpected spool command");
  1341.       break;
  1342.    }
  1343.    return noErr;
  1344. }
  1345.  
  1346.  
  1347. /****    Revert image to last saved image ****/
  1348.  
  1349. #pragma segment fileSys
  1350. OSErr    RevertToSavedFile(ImageDocHndl theDocHndl, WindowPtr theWindow)
  1351. {
  1352.     PicHandle            thePictHndl = nil;
  1353.     PictInfo            thePictInfo;
  1354.     GrafPtr                oldPort;
  1355.     TiffInfo            theTiffStruct;
  1356.     OSErr                error = noErr;
  1357.     
  1358.     (**theDocHndl).theImageChanged = false;
  1359.     if ((**theDocHndl).hasUndoTemp)
  1360.     {
  1361.         RemoveTempFile(theDocHndl, true, false);
  1362.         (**theDocHndl).hasUndoTemp = false;
  1363.     }
  1364.     if ((**theDocHndl).hasRedoTemp)
  1365.     {
  1366.         RemoveTempFile(theDocHndl, false, true);
  1367.         (**theDocHndl).hasRedoTemp = false;
  1368.     }
  1369.     (**theDocHndl).theUndoState = kCannotUndo;
  1370.     if ((**theDocHndl).theImageWorld)
  1371.         DisposeGWorld((**theDocHndl).theImageWorld);
  1372.     if ((**theDocHndl).theColorsPalette)
  1373.         DisposePalette((**theDocHndl).theColorsPalette);
  1374.     if ((**theDocHndl).isUsingQDGX)
  1375.     {
  1376.         GXDisposeShape((**theDocHndl).theGXImageShape);
  1377.         GXDisposeInk((**theDocHndl).theInkShape);
  1378.         GXDisposeViewPort((**theDocHndl).theGxChildView);
  1379.         GXDisposeViewPort((**theDocHndl).theGXview);
  1380.     }
  1381.     switch ((*theDocHndl)->theFileType)
  1382.     {
  1383.         case TiffType:
  1384.             theTiffStruct.tiffCTabHndl = nil;        // set to nil as Color table not always created
  1385.             GetTIFFHdrInfo(theDocHndl,&theTiffStruct);
  1386.             GetTIFFIFDirectory(theDocHndl,&theTiffStruct);
  1387.             switch (theTiffStruct.bitDepth)
  1388.             {
  1389.                 case 8:
  1390.                     (**theDocHndl).theImageWorld = 
  1391.                         CreateOffscreen(theTiffStruct.tiffCTabHndl,
  1392.                                         theTiffStruct.xImageSize,
  1393.                                         theTiffStruct.yImageSize,
  1394.                                         theTiffStruct.bitDepth,kNoFlags);
  1395.                     if ((**theDocHndl).theImageWorld == nil)
  1396.                     {
  1397.                         DisposeHandle((Handle)theDocHndl);
  1398.                         return kFailMakeGWorld;
  1399.                     }
  1400.                 break;
  1401.                 case 32:
  1402.                     (**theDocHndl).theImageWorld = 
  1403.                         CreateOffscreen(nil,
  1404.                                         theTiffStruct.xImageSize,
  1405.                                         theTiffStruct.yImageSize,
  1406.                                         theTiffStruct.bitDepth,kNoFlags);
  1407.                     if ((**theDocHndl).theImageWorld == nil)
  1408.                     {    
  1409.                         DisposeHandle((Handle)theDocHndl);
  1410.                         return kFailMakeGWorld;
  1411.                     }
  1412.                 break;
  1413.                 default:
  1414.                     DisplayAlert (rGenWarning,rErrMessages,iNoSupportBitDepth);
  1415.                     return kBitDepthErr;
  1416.                 break;
  1417.             }
  1418.             error = LoadTiffToGWorld (theDocHndl,&theTiffStruct,theTiffStruct.bitDepth);
  1419.             if (error)
  1420.             {
  1421.                 DisplayAlert (rGenAlert,0,0);
  1422.                 return error;
  1423.             }
  1424.             SetUndoItemText((*theDocHndl)->theUndoState);
  1425.         break;
  1426.         case PictType:
  1427.             thePictHndl = LoadPictImageFile(theDocHndl);
  1428.             if (!thePictHndl)
  1429.             {
  1430.                 DisposeHandle((Handle)theDocHndl);
  1431.                 return kDefaultAppError;
  1432.             }
  1433.             // test if minimal temp memory free available. If none available GetPictInfo() fails.
  1434.             if (TempFreeMem() < kMinLowMem)
  1435.             {
  1436.                 DisplayAlert(rGenWarning,rErrMessages,iLowTempMem);
  1437.                 DisposeHandle((Handle)theDocHndl);
  1438.                 return kLowMemWarning;
  1439.             }
  1440.             error = GetPictInfo (thePictHndl, &thePictInfo, returnColorTable,256,systemMethod,0);
  1441.             if (!error && thePictInfo.depth <= 8)
  1442.                 (**theDocHndl).theImageWorld = 
  1443.                     CreateOffscreen(thePictInfo.theColorTable,
  1444.                                     (**theDocHndl).theImageXSize,
  1445.                                     (**theDocHndl).theImageYSize,
  1446.                                     (**theDocHndl).theImageDepth,kNoFlags);
  1447.             else
  1448.                 (**theDocHndl).theImageWorld = 
  1449.                     CreateOffscreen(nil,
  1450.                                     (**theDocHndl).theImageXSize,
  1451.                                     (**theDocHndl).theImageYSize,
  1452.                                     (**theDocHndl).theImageDepth,kNoFlags);
  1453.             
  1454.             if ((**theDocHndl).theImageWorld == nil)
  1455.             {
  1456.                 DisposeHandle((Handle)theDocHndl);        // dispose image document
  1457.                 DisposeHandle((Handle)thePictHndl);        // dispose picHandle
  1458.                 return kFailMakeGWorld;
  1459.             }
  1460.             error = DrawPictToGWorld (theDocHndl,thePictHndl);
  1461.             SetUndoItemText((*theDocHndl)->theUndoState);
  1462.         break;
  1463.         case GXType:
  1464.             DisplayAlert(rGenWarning,rErrMessages,iNotImplemented);
  1465.             return noErr;
  1466.         break;
  1467.     }
  1468.     GetPort(&oldPort);
  1469.     SetPort(theWindow);
  1470.     InvalRect(&theWindow->portRect);
  1471.     SetPort(oldPort);
  1472.     return error;
  1473. }
  1474.  
  1475.  
  1476. /****    Clean up after abort TIFF load    ****/
  1477.  
  1478. #pragma segment fileSys
  1479. void CleanLoadAbort(ImageDocHndl theDocHndl)
  1480. {
  1481.     if ((**theDocHndl).theColorsPalette)
  1482.         DisposePalette((**theDocHndl).theColorsPalette);
  1483.     DisposeHandle((Handle)theDocHndl);
  1484. }